package middleware

import (
	"errors"
	"net/http"
	"strings"
	"time"

	"admin-glm-go/internal/database"
	"admin-glm-go/internal/models"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

// CORSMiddleware CORS中间件，处理跨域请求
func CORSMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin")
		
		if origin != "" {
			// 设置允许跨域的请求头
			c.Header("Access-Control-Allow-Origin", origin)
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, Token")
			c.Header("Access-Control-Expose-Headers", "Content-Length")
			c.Header("Access-Control-Allow-Credentials", "true")
		}

		// 放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}

		// 处理请求
		c.Next()
	}
}

// JWTClaims JWT声明结构体
type JWTClaims struct {
	UserID   uint64   `json:"userId"`
	Username string   `json:"username"`
	Roles    []string `json:"roles"`
	IssuedAt int64    `json:"iat"`
	ExpiresAt int64   `json:"exp"`
}

// Valid 实现jwt.Claims接口的Valid方法
func (c JWTClaims) Valid() error {
	if time.Now().Unix() > c.ExpiresAt {
		return errors.New("token已过期")
	}
	return nil
}

// GetExpirationTime 实现jwt.Claims接口的GetExpirationTime方法
func (c JWTClaims) GetExpirationTime() (*jwt.NumericDate, error) {
	return jwt.NewNumericDate(time.Unix(c.ExpiresAt, 0)), nil
}

// GetIssuedAt 实现jwt.Claims接口的GetIssuedAt方法
func (c JWTClaims) GetIssuedAt() (*jwt.NumericDate, error) {
	return jwt.NewNumericDate(time.Unix(c.IssuedAt, 0)), nil
}

// GetNotBefore 实现jwt.Claims接口的GetNotBefore方法
func (c JWTClaims) GetNotBefore() (*jwt.NumericDate, error) {
	return jwt.NewNumericDate(time.Unix(c.IssuedAt, 0)), nil
}

// GetIssuer 实现jwt.Claims接口的GetIssuer方法
func (c JWTClaims) GetIssuer() (string, error) {
	return "", nil
}

// GetSubject 实现jwt.Claims接口的GetSubject方法
func (c JWTClaims) GetSubject() (string, error) {
	return "", nil
}

// GetAudience 实现jwt.Claims接口的GetAudience方法
func (c JWTClaims) GetAudience() (jwt.ClaimStrings, error) {
	return jwt.ClaimStrings{}, nil
}

// JWTAuth JWT认证中间件
func JWTAuth(secret string) gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code":    401,
				"message": "请提供认证token",
				"data":    nil,
			})
			c.Abort()
			return
		}

		// 解析Bearer Token
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code":    401,
				"message": "token格式错误",
				"data":    nil,
			})
			c.Abort()
			return
		}

		// 解析token
		claims, err := ParseToken(parts[1], secret)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code":    401,
				"message": "无效的token",
				"data":    nil,
			})
			c.Abort()
			return
		}

		// 将用户信息保存到上下文
		c.Set("userId", claims.UserID)
		c.Set("username", claims.Username)
		c.Set("roles", claims.Roles)
		c.Next()
	}
}

// GenerateToken 生成JWT token
func GenerateToken(user *models.Admin, secret string) (string, error) {
	// 获取用户角色
	var roles []string
	for _, role := range user.Roles {
		roles = append(roles, role.Code)
	}

	// 创建JWT声明
	claims := JWTClaims{
		UserID:    user.ID,
		Username:  user.Username,
		Roles:     roles,
		IssuedAt:  time.Now().Unix(),
		ExpiresAt: time.Now().Add(24 * time.Hour).Unix(), // 24小时过期
	}

	// 创建token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString([]byte(secret))
}

// ParseToken 解析JWT token
func ParseToken(tokenString string, secret string) (*JWTClaims, error) {
	// 解析token
	token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(secret), nil // 从配置中获取
	})

	if err != nil {
		return nil, err
	}

	// 验证token并获取声明
	if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("无效的token")
}

// GetCurrentUser 获取当前登录用户
func GetCurrentUser(c *gin.Context) (*models.Admin, error) {
	userID, exists := c.Get("userId")
	if !exists {
		return nil, nil
	}

	var admin models.Admin
	if err := database.GetDB().Preload("Roles").First(&admin, userID).Error; err != nil {
		return nil, err
	}

	return &admin, nil
}

// HasPermission 检查用户是否有指定权限
func HasPermission(c *gin.Context, permissionCode string) bool {
	// 获取当前用户
	user, err := GetCurrentUser(c)
	if err != nil || user == nil {
		return false
	}

	// 超级管理员拥有所有权限
	for _, role := range user.Roles {
		if role.Code == "super_admin" {
			return true
		}
	}

	// 检查用户角色权限
	for _, role := range user.Roles {
		for _, permission := range role.Permissions {
			if permission.Code == permissionCode {
				return true
			}
		}
	}

	return false
}

// PermissionAuth 权限认证中间件
func PermissionAuth(permissionCode string) gin.HandlerFunc {
	return func(c *gin.Context) {
		if !HasPermission(c, permissionCode) {
			c.JSON(http.StatusForbidden, gin.H{
				"code":    403,
				"message": "没有权限访问此资源",
				"data":    nil,
			})
			c.Abort()
			return
		}
		c.Next()
	}
}

// OperationLog 操作日志中间件
func OperationLog() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 开始时间
		startTime := time.Now()

		// 处理请求
		c.Next()

		// 结束时间
		endTime := time.Now()

		// 执行时间
		execTime := endTime.Sub(startTime)

		// 获取当前用户
		var userID *uint64
		var username string
		if user, exists := c.Get("userId"); exists {
			uid := user.(uint64)
			userID = &uid
		}
		if name, exists := c.Get("username"); exists {
			username = name.(string)
		}

		// 记录操作日志
		log := models.OperationLog{
			AdminID:   userID,
			AdminName: username,
			IP:        c.ClientIP(),
			Url:       c.Request.URL.Path,
			Method:    c.Request.Method,
			Params:    c.Request.Form.Encode(),
			Status:    1, // 默认成功
		}

		// 如果响应状态码不是200，则记录为失败
		if c.Writer.Status() != http.StatusOK {
			log.Status = 0
		}

		// 保存日志
		database.GetDB().Create(&log)
		
		// 使用execTime变量以避免未使用变量的错误
		_ = execTime
	}
}